package com.aconcagua.beans {
  import com.aconcagua.factory.BeanFactory;

  public class BeanDefinitionSupport implements BeanDefinition {
    public static const SCOPE_PROTOTYPE: String = "prototype";
    public static const SCOPE_SINGLETON: String = "singleton";
     
    private var _name: String;
    private var _type: Class;
    private var _lazy: Boolean;
    
    private var _constructorArgs: Array;
    private var _properties: Array;

    private var _scope:String;

    
    public function BeanDefinitionSupport(beanType: Class, theName:String = null) {
      _name = theName;
      _type = beanType;
      _constructorArgs = new Array()
      _properties = new Array();
      scope = SCOPE_SINGLETON;
    }
    
    public function get name(): String {
      return _name;
    }
    
    public function set name(aName: String): void {
      _name = aName;
    }
    
    public function get type(): Class {
      return _type;
    }
    
    public function get lazy(): Boolean {
      return _lazy;
    }
    
    public function set lazy(isLazy: Boolean): void {
      _lazy = isLazy;
    }
    
    public function get scope(): String {
      return _scope;
    }
    
    [Inspectable(enumeration="singleton,prototype", defaultValue="singleton")]
    public function set scope(aScope: String): void {
      _scope = aScope;
    }
    
     public function set metadata(meta: Array): void {
      for each(var beanMetadata:BeanMetadata in meta) {
        beanMetadata.registerIn(this);
      }
    }

    public function get isSingleton(): Boolean {
      return scope == SCOPE_SINGLETON;
    }
    
    public function get isPrototype(): Boolean {
      return scope == SCOPE_PROTOTYPE;
    }
    
    public function addConstructorArg(arg: ConstructorArg): void {
      _constructorArgs.push(arg);
    }

    public function addProperty(property: Property): void {
      _properties.push(property);
    }
    
    public function createInstance(factory: BeanFactory): Object {
      var args:Array = new Array();
      for each (var arg:ConstructorArg in _constructorArgs) {
        args.push(arg.getValue(factory));
      }
      
      //I know this is ugly, but as far as I know actionscript 3 does not support any other way
      switch(args.length) {
        case  0: return new type();
        case  1: return new type(args[0]);
        case  2: return new type(args[0], args[1]);
        case  3: return new type(args[0], args[1], args[2]);
        case  4: return new type(args[0], args[1], args[2], args[3]);
        case  5: return new type(args[0], args[1], args[2], args[3], args[4]);
        case  6: return new type(args[0], args[1], args[2], args[3], args[4], args[5]);
        case  7: return new type(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
        case  8: return new type(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
        case  9: return new type(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
        case 10: return new type(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
      }
      throw new Error("Cannot instantiate classes with more than 10 parameters in the constructor");
    }

    public function applyProperties(beanInstance: Object, factory: BeanFactory): void {
      for each(var property: Property in _properties) {
        property.setTo(beanInstance, factory);
      }
    }
  }
}